package cn.itsource.ymcc.service.impl;

import cn.itsource.constants.RedisConstants;
import cn.itsource.handler.GlobalCustomerException;
import cn.itsource.util.StrUtils;
import cn.itsource.ymcc.domain.MessageSms;
import cn.itsource.ymcc.dto.SMSCode2RedisDTO;
import cn.itsource.ymcc.dto.SMSSendDTO;
import cn.itsource.ymcc.properties.SmsCodeProperties;
import cn.itsource.ymcc.service.IMessageSmsService;
import cn.itsource.ymcc.service.IVerifyCodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author Eric Chen
 * @since 2022/7/10
 */
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate ;

    @Autowired
    private IMessageSmsService smsService ;

    @Autowired
    private SmsCodeProperties properties;


    /**
     * 发送短信验证码
     * 1.参数校验 ， 校验图片验证码(Redis)
     *
     * 2.获取上一次的短信验证码
     * 2.1.有，判断当前时间和上次时间差，大于60S
     * 2.2.小于，报错
     * 2.3.大于，拿出验证码再发一次
     *
     * 3.没有上次创建短信验证码：随机6位数字
     *
     * 4.存储到Redis,key=前缀：手机号  value=验证码+发送时间 ， 设置过期时间
     * 5.调用短信网关发送验证码
     * 6.保存发送日志到DB
     *
     * @param dto ：参数
     */
    @Override
    public void sendSmsCode(SMSSendDTO dto) {
        //1.参数校验 ， 校验图片验证码(Redis)
        //TODO
        //2.获取上一次的短信验证码
        //当前时间
        Date nowDate = new Date();
        //Redis的key
        String key = String.format(RedisConstants.KEY_SMS_CODE_PREFIX, dto.getMobile());
        SMSCode2RedisDTO lastSend = (SMSCode2RedisDTO)redisTemplate.opsForValue().get(key);

        //要发送到验证码
        String smsCode = null;

        if(lastSend != null){
            Long lastSendSendTime = lastSend.getSendTime();
            //2.1.有，判断当前时间和上次时间差，大于60S
            if((nowDate.getTime() - lastSendSendTime) / 1000 < properties.getTwiceinterval()){
                //2.2.小于60S，报错
                throw new GlobalCustomerException("手速太快，稍后再来");
            }
            //2.3.大于，拿出验证码再发一次
            smsCode = lastSend.getCode();
        }else{
            //3.没有上次创建短信验证码：随机6位数字
            smsCode = StrUtils.getRandomString(properties.getLength());
        }
        //4.======================存储到Redis: key=前缀：手机号  value=验证码+发送时间（DTO） ， 设置过期时间====================
        redisTemplate.opsForValue().set(key , new SMSCode2RedisDTO(smsCode , nowDate.getTime()) , properties.getExpire() , TimeUnit.SECONDS);
        //5.调用短信网关发送验证码
        String content = String.format(properties.getContent(), smsCode ,properties.getExpire()/60 );
        log.info(content);
        //6.保存发送日志到DB================================================================================================
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("短信验证码");
        messageSms.setContent(content);
        //获取请求上下文 ， 获取IP地址
        ServletRequestAttributes requestAttributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String remoteAddr = requestAttributes.getRequest().getRemoteAddr();
        messageSms.setIp(remoteAddr);
        messageSms.setPhone(dto.getMobile());
        messageSms.setSendTime(nowDate);
        smsService.insert(messageSms);
    }
}
